home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / 8250.c next >
C/C++ Source or Header  |  1991-03-17  |  17KB  |  761 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * 16550A support plus some statistics added mah@hpuviea.at 15/7/89
  5.  *
  6.  * CTS hardware flow control from dkstevens@ucdavis,
  7.  * additional stats from delaroca@oac.ucla.edu added by karn 4/17/90
  8.  * RLSD flow control reorganized by Bill_Simpson@um.cc.umich.edu; Feb 91
  9.  */
  10. #include <stdio.h>
  11. #include <dos.h>
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "proc.h"
  15. #include "iface.h"
  16. #include "8250.h"
  17. #include "asy.h"
  18. #include "devparam.h"
  19. #include "pc.h"
  20.  
  21. static void asy_rlsd __ARGS((int dev,void *p1,void *p2));
  22.  
  23. static void asy_output __ARGS((int dev,char *buf,unsigned short cnt));
  24. static int asyrxint __ARGS((struct asy *asyp));
  25. static void asytxint __ARGS((int dev));
  26. static void asymsint __ARGS((int dev));
  27.  
  28. static void asy_tx __ARGS((int dev,void *p1,void *p2));
  29.  
  30. struct asy Asy[ASY_MAX];
  31.  
  32. /* ASY interrupt handlers */
  33. static INTERRUPT (*Handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec};
  34.  
  35.  
  36. /* Initialize asynch port "dev" */
  37. int
  38. asy_init(dev,iface,arg1,arg2,bufsize,trigchar,cts,rlsd,speed)
  39. int dev;
  40. struct iface *iface;
  41. char *arg1,*arg2;    /* Attach args for address and vector */
  42. int16 bufsize;
  43. int trigchar;
  44. char cts;
  45. char rlsd;
  46. int16 speed;
  47. {
  48.     register unsigned base;
  49.     register struct fifo *fp;
  50.     register struct asy *ap;
  51.     char *ifn;
  52.     char i_state;
  53.  
  54.     ap = &Asy[dev];
  55.     ap->iface = iface;
  56.     ap->addr = htoi(arg1);
  57.     ap->vec = htoi(arg2);
  58.     ap->cts_flow_control = cts;
  59.  
  60.     /* set up to monitor rlsd (carrier detect) */
  61.     if ( rlsd ) {
  62.         ap->rlsd_line_control = RLSD_DOWN;
  63.         ifn = if_name(iface," rlsd");
  64.         newproc(ifn, 256, asy_rlsd, dev, NULL,NULL,0);
  65.         free(ifn);
  66.         pwait(NULL);
  67.     } else {
  68.         ap->rlsd_line_control = RLSD_NONE;
  69.     }
  70.  
  71.     /* Set up receiver FIFO */
  72.     fp = &ap->fifo;
  73.     fp->buf = mallocw(bufsize);
  74.     fp->bufsize = bufsize;
  75.     fp->wp = fp->rp = fp->buf;
  76.     fp->cnt = 0;
  77.     fp->hiwat = 0;
  78.     fp->overrun = 0;
  79.     base = ap->addr;
  80.     ap->trigchar = trigchar;
  81.  
  82.     /* Purge the receive data buffer */
  83.     (void)inportb(base+RBR);
  84.  
  85.     i_state = dirps();
  86.  
  87.     /* Save original interrupt vector, mask state, control bits */
  88.     ap->save.vec = getirq(ap->vec);
  89.     ap->save.mask = getmask(ap->vec);
  90.     ap->save.lcr = inportb(base+LCR);
  91.     ap->save.ier = inportb(base+IER);
  92.     ap->save.mcr = inportb(base+MCR);
  93.  
  94.     /* save speed bytes */
  95.     setbit(base+LCR,LCR_DLAB);
  96.     ap->save.divl = inportb(base+DLL);
  97.     ap->save.divh = inportb(base+DLM);
  98.     clrbit(base+LCR,LCR_DLAB);
  99.  
  100.     /* Set interrupt vector to SIO handler */
  101.     setirq(ap->vec,Handle[dev]);
  102.  
  103.     /* Set line control register: 8 bits, no parity */
  104.     outportb(base+LCR,(char)LCR_8BITS);
  105.  
  106.     /* determine if 16550A, turn on FIFO mode and clear RX and TX FIFOs */
  107.     outportb(base+FCR,(char) FIFO_ENABLE);
  108.  
  109.     /* According to National ap note AN-493, the FIFO in the 16550 chip
  110.      * is broken and must not be used. To determine if this is a 16550A
  111.      * (which has a good FIFO implementation) check that both bits 7
  112.      * and 6 of the IIR are 1 after setting the fifo enable bit. If
  113.      * not, don't try to use the FIFO.
  114.      */
  115.     if ((inportb(base+IIR) & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED) {
  116.         ap->is_16550a = TRUE;
  117.         outportb(base+FCR,(char) FIFO_SETUP);
  118.     } else {
  119.         /* Chip is not a 16550A. In case it's a 16550 (which has a
  120.          * broken FIFO), turn off the FIFO bit.
  121.          */
  122.         outportb(base+FCR,(char)0);
  123.         ap->is_16550a = FALSE;
  124.     }
  125.     if ( rlsd ) {
  126.         /* Turn on modem status interrupt, leave receive
  127.          * and transmit interrupts off until RLSD is asserted
  128.          */
  129.         outportb(base+IER, (char)IER_MS);
  130.         /* DTR and RTS should match the RLSD signal */
  131.         asymsint(dev);
  132.         /* Turn on 8250 master interrupt enable (connected to OUT2) */
  133.         outportb(base+MCR, (char)(MCR_OUT2));
  134.     } else {
  135.         /* Turn on receive interrupt enable in 8250, leave transmit
  136.          * and modem status interrupts turned off for now
  137.          */
  138.         outportb(base+IER,(char)IER_DAV);
  139.  
  140.         /* Set modem control register: assert DTR, RTS, turn on 8250
  141.          * master interrupt enable (connected to OUT2)
  142.          */
  143.         outportb(base+MCR,(char)(MCR_DTR|MCR_RTS|MCR_OUT2));
  144.     }
  145.     /* Enable interrupt */
  146.     maskon(ap->vec);
  147.     restore(i_state);
  148.  
  149.     asy_speed(dev,speed);
  150.  
  151.     ifn = if_name(iface," tx");
  152.     iface->txproc = newproc(ifn,256,asy_tx,dev,NULL,NULL,0);
  153.     free(ifn);
  154.  
  155.     if ( !rlsd ) {
  156.         /* If we're not checking, must assume we're up */
  157.         if ( iface->iostatus != NULL ) {
  158.             (*iface->iostatus)(iface, PARAM_UP, 0L);
  159.         }
  160.     }
  161.     return 0;
  162. }
  163.  
  164.  
  165. int
  166. asy_stop(iface)
  167. struct iface *iface;
  168. {
  169.     register unsigned base;
  170.     register struct asy *ap;
  171.     char i_state;
  172.  
  173.     ap = &Asy[iface->dev];
  174.  
  175.     if ( ap->rlsd_line_control ) {
  176.         ap->rlsd_line_control = RLSD_NONE;
  177.         psignal( &(ap->rlsd_line_control), 0 );
  178.         pwait(NULL);
  179.     }
  180.     ap->iface = NULLIF;
  181.  
  182.     base = ap->addr;
  183.  
  184.     /* Purge the receive data buffer */
  185.     (void)inportb(base+RBR);
  186.  
  187.     /* and hardware fifos if available */
  188.     if (ap->is_16550a)
  189.         outportb(base+FCR,(char) FIFO_SETUP);
  190.  
  191.     /* Restore original interrupt vector and 8259 mask state */
  192.     i_state = dirps();
  193.     setirq(ap->vec,ap->save.vec);
  194.     if(ap->save.mask)
  195.         maskon(ap->vec);
  196.     else
  197.         maskoff(ap->vec);
  198.  
  199.     /* Restore speed regs */
  200.     setbit(base+LCR,LCR_DLAB);
  201.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  202.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  203.     clrbit(base+LCR,LCR_DLAB);
  204.  
  205.     /* Restore control regs */
  206.     outportb(base+LCR,ap->save.lcr);
  207.     outportb(base+IER,ap->save.ier);
  208.     outportb(base+MCR,ap->save.mcr);
  209.     restore(i_state);
  210.     free(ap->fifo.buf);
  211.     return 0;
  212. }
  213.  
  214.  
  215. /* Set asynch line speed */
  216. int
  217. asy_speed(dev,bps)
  218. int dev;
  219. int16 bps;
  220. {
  221.     register unsigned base;
  222.     register long divisor;
  223.     struct asy *asyp;
  224.     char i_state;
  225.  
  226.     if(bps == 0 || dev >= ASY_MAX)
  227.         return -1;
  228.     asyp = &Asy[dev];
  229.     if(asyp->iface == NULLIF)
  230.         return -1;
  231.  
  232.     switch(bps) {
  233.     case 300:
  234.     case 1200:
  235.     case 2400:
  236.     case 4800:
  237.     case 9600:
  238.     case 19200:
  239.         /* supported speed */
  240.         asyp->speed = bps;
  241.         break;
  242.     default:
  243.         /* unsupported speed */
  244.         return -1;
  245.     };
  246.  
  247.     base = asyp->addr;
  248.     divisor = BAUDCLK / bps;
  249.  
  250.     i_state = dirps();
  251.  
  252.     /* Purge the receive data buffer */
  253.     (void)inportb(base+RBR);
  254.     if (asyp->is_16550a)        /* clear tx+rx fifos */
  255.         outportb(base+FCR,(char) FIFO_SETUP);
  256.  
  257.     /* Turn on divisor latch access bit */
  258.     setbit(base+LCR,LCR_DLAB);
  259.  
  260.     /* Load the two bytes of the register */
  261.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  262.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  263.  
  264.     /* Turn off divisor latch access bit */
  265.     clrbit(base+LCR,LCR_DLAB);
  266.  
  267.     restore(i_state);
  268.     return 0;
  269. }
  270.  
  271.  
  272. /* Asynchronous line I/O control */
  273. int32
  274. asy_ioctl(iface,cmd,set,val)
  275. struct iface *iface;
  276. int cmd;
  277. int set;
  278. int32 val;
  279. {
  280.     int16 base = Asy[iface->dev].addr;
  281.  
  282.     switch(cmd){
  283.     case PARAM_SPEED:
  284.         if(set)
  285.             asy_speed(iface->dev,(int16)val);
  286.         return Asy[iface->dev].speed;
  287.     case PARAM_DTR:
  288.         if(set)
  289.             writebit(base+MCR,MCR_DTR,(int)val);
  290.         return (inportb(base+MCR) & MCR_DTR) ? TRUE : FALSE;
  291.     case PARAM_RTS:
  292.         if(set)
  293.             writebit(base+MCR,MCR_RTS,(int)val);
  294.         return (inportb(base+MCR) & MCR_RTS) ? TRUE : FALSE;
  295.         case PARAM_DOWN:
  296.             clrbit(base+IER,(char)IER_DAV);
  297.             clrbit(base+MCR,MCR_RTS);
  298.             clrbit(base+MCR,MCR_DTR);
  299.             return FALSE;
  300.         case PARAM_UP:
  301.             setbit(base+IER,(char)IER_DAV);
  302.             setbit(base+MCR,MCR_RTS);
  303.             setbit(base+MCR,MCR_DTR);
  304.             return TRUE;
  305.     };
  306.     return -1;
  307. }
  308.  
  309.  
  310. /* Start transmission of a buffer on the serial transmitter */
  311. static void
  312. asy_output(dev,buf,cnt)
  313. int dev;
  314. char *buf;
  315. unsigned short cnt;
  316. {
  317.     register struct dma *dp;
  318.     unsigned base;
  319.     char i_state;
  320.     char ier;
  321.     struct asy *asyp;
  322.  
  323.     if(dev < 0 || dev >= ASY_MAX)
  324.         return;
  325.     asyp = &Asy[dev];
  326.     if(asyp->iface == NULLIF)
  327.         return;
  328.     base = asyp->addr;
  329.     dp = &asyp->dma;
  330.     i_state = dirps();
  331.     if(dp->flags){
  332.         restore(i_state);
  333.         return;    /* Already busy */
  334.     }
  335.     dp->data = buf;
  336.     dp->cnt = cnt;
  337.     dp->flags = 1;
  338.  
  339.     if(asyp->cts_flow_control){
  340.         /* CTS flow control is enabled; let the modem control
  341.          * interrupt enable transmit interrupts if CTS is off
  342.          */
  343.         ier = IER_MS;
  344.         if(inportb(base+MSR) & MSR_CTS)
  345.             ier |= IER_TxE;
  346.     } else {
  347.         /* Enable transmit interrupts; this will cause an immediate
  348.          * interrupt that will start things going
  349.          */
  350.         ier = IER_TxE;
  351.     }
  352.     setbit(base+IER,ier);
  353.     /* "Kick start" the transmitter interrupt routine, in case just
  354.      * setting the interrupt enable bit doesn't case an interrupt
  355.      */
  356.     if(ier & IER_TxE)
  357.         asytxint(dev);
  358.     restore(i_state);
  359. }
  360.  
  361.  
  362. /* Blocking read from asynch line
  363.  * Returns character or -1 if aborting
  364.  */
  365. int
  366. get_asy(dev)
  367. int dev;
  368. {
  369.     char i_state;
  370.     register struct fifo *fp;
  371.     char c;
  372.  
  373.     fp = &Asy[dev].fifo;
  374.  
  375.     i_state = dirps();
  376.     while(fp->cnt == 0){
  377.         if(pwait(fp) != 0){
  378.             restore(i_state);
  379.             return -1;
  380.         }
  381.     }
  382.     fp->cnt--;
  383.     restore(i_state);
  384.  
  385.     c = *fp->rp++;
  386.     if(fp->rp >= &fp->buf[fp->bufsize])
  387.         fp->rp = fp->buf;
  388.  
  389.     return uchar(c);
  390. }
  391.  
  392.  
  393. /* Interrupt handler for 8250 asynch chip (called from asyvec.asm) */
  394. void
  395. asyint(dev)
  396. int dev;
  397. {
  398.     struct asy *asyp;
  399.     unsigned base;
  400.     char iir;
  401.  
  402.     asyp = &Asy[dev];
  403.     base = asyp->addr;
  404.     while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  405.         switch(iir & IIR_ID){
  406.         case IIR_RDA:    /* Receiver interrupt */
  407.             asyrxint(asyp);
  408.             break;
  409.         case IIR_THRE:    /* Transmit interrupt */
  410.             asytxint(dev);
  411.             break;
  412.         case IIR_MSTAT:    /* Modem status change */
  413.             asymsint(dev);
  414.             asyp->cts_flow_ints++;
  415.             break;
  416.         }
  417.         /* should happen at end of a single slip packet */
  418.         if(iir & IIR_FIFO_TIMEOUT)
  419.             asyp->fifotimeouts++;
  420.     }
  421. }
  422.  
  423.  
  424. /* Process 8250 receiver interrupts */
  425. static int
  426. asyrxint(asyp)
  427. struct asy *asyp;
  428. {
  429.     register struct fifo *fp;
  430.     unsigned base;
  431.     char c,lsr;
  432.     int cnt = 0;
  433.     int trigseen = FALSE;
  434.  
  435.     asyp->rxints++;
  436.     base = asyp->addr;
  437.     fp = &asyp->fifo;
  438.     for(;;){
  439.         lsr = inportb(base+LSR);
  440.         if(lsr & LSR_OE)
  441.             asyp->overrun++;
  442.  
  443.         if(lsr & LSR_DR){
  444.             asyp->rxchar++;
  445.             c = inportb(base+RBR);
  446.             if(asyp->trigchar == uchar(c))
  447.                 trigseen = TRUE;
  448.             /* If buffer is full, we have no choice but
  449.              * to drop the character
  450.              */
  451.             if(fp->cnt != fp->bufsize){
  452.                 *fp->wp++ = c;
  453.                 if(fp->wp >= &fp->buf[fp->bufsize])
  454.                     /* Wrap around */
  455.                     fp->wp = fp->buf;
  456.                 fp->cnt++;
  457.                 if(fp->cnt > fp->hiwat)
  458.                     fp->hiwat = fp->cnt;
  459.                 cnt++;
  460.             } else
  461.                 fp->overrun++;
  462.         } else
  463.             break;
  464.     }
  465.     if(cnt > asyp->rxhiwat)
  466.         asyp->rxhiwat = cnt;
  467.     if(trigseen)
  468.         psignal(fp,1);
  469.     return cnt;
  470. }
  471.  
  472.  
  473. /* Handle 8250 transmitter interrupts */
  474. static void
  475. asytxint(dev)
  476. int dev;
  477. {
  478.     register struct dma *dp;
  479.     register unsigned base;
  480.     register int count;
  481.     struct asy *asyp;
  482.  
  483.     asyp = &Asy[dev];
  484.     base = asyp->addr;
  485.     dp = &asyp->dma;
  486.     asyp->txints++;
  487.     if(!dp->flags){
  488.         /* "Shouldn't happen", but disable transmit
  489.          * interrupts anyway
  490.          */
  491.         clrbit(base+IER,IER_TxE);
  492.         return;    /* Nothing to send */
  493.     }
  494.     if(!(inportb(base+LSR) & LSR_THRE))
  495.         return;    /* Not really ready */
  496.  
  497.     /* If it's a 16550A, load up to 16 chars into the tx hw fifo
  498.      * at once. With an 8250, it can be one char at most.
  499.      */
  500.     if(asyp->is_16550a){
  501.         count = min(dp->cnt,OUTPUT_FIFO_SIZE);
  502.  
  503.         /* 16550A: LSR_THRE will drop after the first char loaded
  504.          * so we can't look at this bit to determine if the hw fifo is
  505.          * full. There seems to be no way to determine if the tx fifo
  506.          * is full (any clues?). So we should never get here while the
  507.          * fifo isn't empty yet.
  508.          */
  509.         asyp->txchar += count;
  510.         dp->cnt -= count;
  511. #ifdef    notdef    /* This is apparently too fast for some chips */
  512.         dp->data = outbuf(base+THR,dp->data,count);
  513. #else
  514.         while(count-- != 0)
  515.             outportb(base+THR,*dp->data++);
  516. #endif
  517.         if(dp->cnt == 0){
  518.             dp->flags = 0;
  519.             /* Disable transmit interrupts */
  520.             clrbit(base+IER,IER_TxE);
  521.             psignal(asyp,1);
  522.         }
  523.     } else {    /* 8250 */
  524.         do {
  525.             asyp->txchar++;
  526.             outportb(base+THR,*dp->data++);
  527.  
  528.             if(--dp->cnt == 0){
  529.                 dp->flags = 0;
  530.                 /* Disable transmit interrupts */
  531.                 clrbit(base+IER,IER_TxE);
  532.                 psignal(asyp,1);
  533.                 break;
  534.             }
  535.         } while(inportb(base+LSR) & LSR_THRE);
  536.     }
  537. }
  538.  
  539.  
  540. /* Handle 8250 modem status change */
  541. static void
  542. asymsint(dev)
  543. int dev;
  544. {
  545.     char msr;
  546.     unsigned base;
  547.     struct asy *asyp;
  548.     struct dma *dp;
  549.  
  550.     asyp = &Asy[dev];
  551.     base = asyp->addr;
  552.     msr = inportb(base+MSR);
  553.     dp = &asyp->dma;
  554.  
  555.     /* Check status of modem control signals from remote host */
  556.     if (asyp->rlsd_line_control) {
  557.         if (msr & MSR_RLSD) {
  558.             /* RLSD is asserted */
  559.             if (asyp->rlsd_line_control == RLSD_DOWN) {
  560.                 /* RLSD just went up */
  561.                 asyp->rlsd_line_control = RLSD_UP;
  562.                 psignal( &(asyp->rlsd_line_control), 1 );
  563.             }
  564.         } else {
  565.             /* RLSD not asserted */
  566.             if (asyp->rlsd_line_control == RLSD_UP) {
  567.                 /* RLSD just went down */
  568.                 asyp->rlsd_line_control = RLSD_DOWN;
  569.                 psignal( &(asyp->rlsd_line_control), 1 );
  570.             }
  571.         }
  572.     }
  573.     if (asyp->cts_flow_control) {
  574.         if(msr & MSR_CTS){
  575.             /* CTS now asserted, enable Transmit interrupts */
  576.             if(dp->flags)
  577.                 setbit(base+IER,IER_TxE);
  578.         } else {
  579.             /* CTS now dropped, disable Transmit interrupts */
  580.             clrbit(base+IER,IER_TxE);
  581.         }
  582.     }
  583. }
  584.  
  585.  
  586. /* Wait for a signal that the RLSD modem status has changed */
  587. int
  588. get_rlsd_asy(dev, new_rlsd)
  589. int dev;
  590. int new_rlsd;
  591. {
  592.     struct asy *ap = &Asy[dev];
  593.     struct iface *ifp = ap->iface;
  594.     int result;
  595.  
  596.     if (new_rlsd == RLSD_NONE)
  597.         /* Just return the current value */
  598.         return(ap->rlsd_line_control);
  599.  
  600.     if (ap->rlsd_line_control == new_rlsd)
  601.         /* Already at requested value */
  602.         return(new_rlsd);
  603.  
  604.     /* Wait for state change to requested value */
  605.     while (ap->rlsd_line_control != new_rlsd) {
  606.         pwait( &(ap->rlsd_line_control) );
  607.         pause(2L);
  608.     }
  609.  
  610.     if ( ap->rlsd_line_control == RLSD_UP )
  611.         result = PARAM_UP;
  612.     else
  613.         result = PARAM_DOWN;
  614.  
  615.     if ( ifp->ioctl != NULL )
  616.         (*ifp->ioctl)( ifp, result, TRUE, 0L );
  617.     if ( ifp->iostatus != NULLFP )
  618.         (*ifp->iostatus)( ifp, result, 0L );
  619.     if ( ifp->supv != NULLPROC )
  620.         alert( ifp->supv, 0 );
  621.     return(ap->rlsd_line_control);
  622. }
  623.  
  624.  
  625. /* Monitor RLSD signal, and report status changes */
  626. static void
  627. asy_rlsd( dev, p1, p2 )
  628. int dev;
  629. void *p1;
  630. void *p2;
  631. {
  632.     int save_rlsd = Asy[dev].rlsd_line_control;
  633.  
  634.     while ( save_rlsd != RLSD_NONE ) {
  635.         if ( save_rlsd != RLSD_UP ) {
  636.             save_rlsd = get_rlsd_asy( dev, RLSD_UP );
  637.         } else {
  638.             save_rlsd = get_rlsd_asy( dev, RLSD_DOWN );
  639.         }
  640.     }
  641. }
  642.  
  643.  
  644. /* Poll the asynch input queues; called on every clock tick.
  645.  * This helps limit the interrupt ring buffer occupancy when long
  646.  * packets are being received.
  647.  */
  648. void
  649. asytimer()
  650. {
  651.     register struct asy *asyp;
  652.     register struct fifo *fp;
  653.     register int i;
  654.  
  655.     for(i=0;i<ASY_MAX;i++){
  656.         asyp = &Asy[i];
  657.         fp = &asyp->fifo;
  658.         if(fp->cnt != 0)
  659.             psignal(fp,1);
  660.         if(asyp->dma.flags != 0 && (inportb(asyp->addr+LSR) & LSR_THRE) ) {
  661.             asyp->txto++;
  662.             asytxint(asyp->iface->dev);
  663.         }
  664.     }
  665. }
  666. int
  667. doasystat(argc,argv,p)
  668. int argc;
  669. char *argv[];
  670. void *p;
  671. {
  672.     register struct asy *asyp;
  673.  
  674.     for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
  675.         if(asyp->iface == NULLIF)
  676.             continue;
  677.  
  678.         tprintf("%s:",asyp->iface->name);
  679.         if(asyp->is_16550a)
  680.             tprintf(" [NS16550A]");
  681.         if(asyp->trigchar != -1)
  682.             tprintf(" [trigger 0x%02x]",asyp->trigchar);
  683.         if(asyp->cts_flow_control)
  684.             tprintf(" [cts flow control]");
  685.         if(asyp->rlsd_line_control)
  686.             tprintf(" [rlsd line control]");
  687.         tprintf(" %u bps\n",asyp->speed);
  688.  
  689.         tprintf(" RX: %lu int, %lu chr, %lu hw over, %lu hw hi,",
  690.             asyp->rxints,
  691.             asyp->rxchar,
  692.             asyp->overrun,
  693.             asyp->rxhiwat);
  694.         asyp->rxhiwat = 0;
  695.         if(asyp->is_16550a)
  696.             tprintf(" %lu fifo TO,",asyp->fifotimeouts);
  697.         tprintf(" %lu sw over, %u sw hi\n",
  698.             asyp->fifo.overrun,
  699.             asyp->fifo.hiwat);
  700.         asyp->fifo.hiwat = 0;
  701.  
  702.         if(tprintf(" TX: %lu int, %lu chr, %u q, %lu CTS/RLSD, %lu THRE TO\n",
  703.             asyp->txints,
  704.             asyp->txchar,
  705.             len_q(asyp->sndq),
  706.             asyp->cts_flow_ints,
  707.             asyp->txto) == EOF)
  708.             break;
  709.     }
  710.     return 0;
  711. }
  712. /* Send a message on the specified serial line */
  713. int
  714. asy_send(dev,bp)
  715. int dev;
  716. struct mbuf *bp;
  717. {
  718.     if(dev < 0 || dev >= ASY_MAX)
  719.         return -1;
  720.     enqueue(&Asy[dev].sndq,bp);
  721.     return 0;
  722. }
  723.  
  724. /* Serial transmit process, common to all protocols */
  725. static void
  726. asy_tx(dev,p1,p2)
  727. int dev;
  728. void *p1;
  729. void *p2;
  730. {
  731.     register struct mbuf *bp;
  732.     struct asy *asyp;
  733.     struct dma *dp;
  734.     int i_state;
  735.  
  736.     asyp = &Asy[dev];
  737.     dp = &asyp->dma;
  738.  
  739.     for(;;){
  740.         /* Fetch a buffer for transmission */
  741.         while(asyp->sndq == NULLBUF)
  742.             pwait(&asyp->sndq);
  743.  
  744.         bp = dequeue(&asyp->sndq);
  745.  
  746.         while(bp != NULLBUF){
  747.             /* Start the transmitter */
  748.             asy_output(dev,bp->data,bp->cnt);
  749.  
  750.             /* Wait for completion */
  751.             i_state = dirps();
  752.             while(dp->flags == 1)
  753.                 pwait(asyp);
  754.             restore(i_state);
  755.  
  756.             /* Now do next buffer on chain */
  757.             bp = free_mbuf(bp);
  758.         }
  759.     }
  760. }
  761.